home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 July: Mac OS SDK / Dev.CD Jul 96 SDK / Dev.CD Jul 96 SDK1.toast / Development Kits (Disc 1) / AOCE / Development Tools / Sample Code / Standard Catalog Package / DTS AddressOMatic / Src / LogManager.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-05  |  12.5 KB  |  528 lines  |  [TEXT/KAHL]

  1. /*                                    LogManager.c                                */
  2. /*
  3.  * LogManager.c
  4.  * Copyright © 1993 Apple Computer Inc. All rights reserved.
  5.  *
  6.  * These functions manage a logging display for error messages and other text.
  7.  * The log is implemented as a ListManager list that can hold nLogItems. This
  8.  * module is intentionally more-or-less self-contained so it can easily be
  9.  * exported to other applications.
  10.  */
  11. #include "LogManager.h"
  12. #include <Packages.h>
  13. /*
  14.  * There is a 32000 byte maximum for the list, so don't
  15.  * make nLogLines too big.
  16.  */
  17. #ifndef nDefaultLogLines
  18. #define nDefaultLogLines    128
  19. #endif
  20. #ifndef kScrollBarWidth
  21. #define kScrollBarWidth            16
  22. #endif
  23. #define kCharEllipsis            0xC9        /* ...    */
  24. #define width(r)                ((r).right - (r).left)
  25. #define height(r)                ((r).bottom - (r).top)
  26. #ifndef TRUE
  27. #define TRUE                    1
  28. #define FALSE                    0
  29. #endif
  30.  
  31. /*
  32.  * Cheap 'n dirty pascal string copy routine.
  33.  */
  34. #ifndef pstrcpy
  35. #define pstrcpy(dst, src) do {                            \
  36.         StringPtr    _src = (src);                        \
  37.         BlockMove(_src, dst, _src[0] + 1);                \
  38.     } while (0)
  39. #endif
  40. /*
  41.  * Cheap 'n dirty pascal string concat.
  42.  */
  43. #ifndef pstrcat
  44. #define pstrcat(dst, src) do {                            \
  45.         StringPtr        _dst = (dst);                    \
  46.         StringPtr        _src = (src);                    \
  47.         short            _len;                            \
  48.         _len = 255 - _dst[0];                            \
  49.         if (_len > _src[0]) _len = _src[0];                \
  50.         BlockMove(&_src[1], &_dst[1] + _dst[0], _len);    \
  51.         _dst[0] += _len;                                \
  52.     } while (0)
  53. #endif
  54.  
  55. static void                            DrawWideText(
  56.         Ptr                                textPtr,
  57.         unsigned short                    offset,
  58.         unsigned short                    textLength,
  59.         const Rect                        *boundsRect,
  60.         short                            textFace
  61.     );
  62.  
  63.  
  64. /*
  65.  * This record is stored in the userHandle variable in
  66.  * the list. The values are needed to specify the font
  67.  * and limit the number of error log lines that are stored.
  68.  */
  69. typedef struct LogInfoRecord {
  70.         short                logLines;
  71.         short                fontNumber;
  72.         short                fontSize;
  73.         RGBColor            foreColor;
  74.         RGBColor            backColor;
  75. } LogInfoRecord, *LogInfoPtr, **LogInfoHdl;
  76. #define LIST            (**logListHandle)
  77. #define LOGINFO            (**((LogInfoHdl) (LIST.userHandle)))
  78. #define IS_COLOR(port)    (((((CGrafPtr) (port))->portVersion) & 0xC000) != 0)
  79. #define COLOR_LIST        (IS_COLOR(LIST.port))
  80. /*
  81.  * This code sequence is copied into the ListProc handle. It
  82.  * is designed so we don't have to flush the instruction
  83.  * and data caches.
  84.  */
  85. static const short gDummyLDEF[] = {
  86.         0x207A,                /*        movea.l    procPtr,a0            */
  87.         0x0004,                /*                <offset to procPtr>    */
  88.         0x4ED0,                /*        jmp        a0                     */
  89.         0x0000, 0x0000        /*        dc.l    <Drawing Proc here>    */
  90. };
  91.  
  92. static pascal void
  93. LogListDefProc(
  94.         short                            listMessage,
  95.         Boolean                            listSelect,
  96.         Rect                            *listRect,
  97.         Cell                            listCell,
  98.         short                            listDataOffset,
  99.         short                            listDataLen,
  100.         ListHandle                        errorLogList
  101.     );
  102.  
  103. /*
  104.  * Create the data display list.
  105.  */
  106. ListHandle
  107. CreateLog(
  108.         const Rect                        *viewRect,
  109.         short                            listFontNumber,
  110.         short                            listFontSize,
  111.         short                            logLines
  112.     )
  113. {
  114.         OSErr                        status;
  115.         ListHandle                    logListHandle;
  116.         FontInfo                    info;
  117.         Point                        cellSize;
  118.         short                        listHeight;
  119.         Rect                        dataBounds;
  120.         Rect                        listRect;
  121.         short                        listFontHeight;
  122.         Handle                        drawProcHdl;
  123.         LogInfoRecord                logInfo;
  124.         Handle                        logInfoHdl;
  125.         ProcPtr                        listProcPtr;
  126.         
  127.         if (logLines == 0)
  128.             logLines = nDefaultLogLines;
  129.         TextFont(listFontNumber);
  130.         TextSize(listFontSize);
  131.         GetFontInfo(&info);
  132.         listFontHeight = info.ascent + info.descent + info.leading;
  133.         /*
  134.          * Compute the list drawing area, adjusting the list
  135.          * area height so an integral number of lines will be drawn.
  136.          */
  137.         listRect = *viewRect;
  138.         listRect.right -= (kScrollBarWidth - 1);
  139.         listHeight = height(listRect);
  140.         listHeight -= (listHeight % listFontHeight);
  141.         listRect.bottom = listRect.top + listHeight;
  142.         SetPt(&cellSize, width(listRect), listFontHeight);
  143.         /*
  144.          * Create a one-column list.
  145.          */
  146.         SetRect(&dataBounds, 0, 0, 1, 0);
  147.         logInfoHdl = NULL;
  148.         drawProcHdl = NULL;
  149.         logListHandle = LNew(
  150.                 &listRect,                    /* Viewing area        */
  151.                 &dataBounds,                /* Rows and col's    */
  152.                 cellSize,                    /* Element size        */
  153.                 0,                            /* No defProc yet    */
  154.                 qd.thePort,                    /* Display window    */
  155.                 TRUE,                        /* Draw it            */
  156.                 FALSE,                        /* No grow box        */
  157.                 FALSE,                        /* No horiz scroll    */
  158.                 TRUE                        /* Vertical scroll    */
  159.             );
  160.         if (logListHandle == NULL)
  161.             goto failure;
  162.         LIST.selFlags = lOnlyOne;
  163.         LIST.listFlags = lDoVAutoscroll;
  164.         logInfo.logLines = logLines;
  165.         logInfo.fontNumber = listFontNumber;
  166.         logInfo.fontSize = listFontSize;
  167.         if (COLOR_LIST) {
  168.             GetForeColor(&logInfo.foreColor);
  169.             GetBackColor(&logInfo.backColor);
  170.         }
  171.         status = PtrToHand(&logInfo, &logInfoHdl, sizeof logInfo);
  172.         if (status != noErr)
  173.             goto failure;
  174.         LIST.userHandle = (Handle) logInfoHdl;
  175.         status = PtrToHand(gDummyLDEF, &drawProcHdl, sizeof gDummyLDEF);
  176.         if (status != noErr)
  177.             goto failure;
  178.         listProcPtr = (ProcPtr) LogListDefProc;
  179.         BlockMove(&listProcPtr, &((short *) *drawProcHdl)[3], sizeof listProcPtr);
  180.         LIST.listDefProc = drawProcHdl;
  181.         goto success;
  182. failure:
  183.         if (drawProcHdl != NULL)
  184.             DisposeHandle((Handle) drawProcHdl);
  185.         DisposeLog(logListHandle);
  186.         logListHandle = NULL;
  187. success:
  188.         return (logListHandle);
  189. }
  190.  
  191. void
  192. DisposeLog(
  193.         ListHandle                        logListHandle
  194.     )
  195. {
  196.         if (logListHandle != NULL) {
  197.             if (LIST.userHandle != NULL) {
  198.                 DisposeHandle(LIST.userHandle);
  199.                 LIST.userHandle = NULL;
  200.             }
  201.             LDispose(logListHandle);
  202.         }
  203. }
  204.  
  205. void
  206. UpdateLog(
  207.         ListHandle                        logListHandle
  208.     )
  209. {
  210.         Rect                        viewRect;
  211.         RGBColor                    saveForeColor;
  212.         RGBColor                    saveBackColor;
  213.         
  214.         /*
  215.          * Make sure the list is locked down while we draw.
  216.          */        
  217.         if (COLOR_LIST) {
  218.             GetForeColor(&saveForeColor);
  219.             GetBackColor(&saveBackColor);
  220.             RGBForeColor(&LOGINFO.foreColor);
  221.             RGBBackColor(&LOGINFO.backColor);
  222.         }
  223.         viewRect = LIST.rView;
  224.         InsetRect(&viewRect, -1, -1);
  225.         EraseRect(&viewRect);
  226.         FrameRect(&viewRect);
  227.         LUpdate(LIST.port->visRgn, logListHandle);
  228.         if (COLOR_LIST) {
  229.             RGBForeColor(&saveForeColor);
  230.             RGBBackColor(&saveBackColor);
  231.         }
  232. }
  233.  
  234. void
  235. ActivateLog(
  236.         ListHandle                        logListHandle,
  237.         Boolean                            activating
  238.     )
  239. {
  240.         LActivate(activating, logListHandle);
  241. }
  242.  
  243. void
  244. MoveLog(
  245.         ListHandle                        logListHandle,
  246.         short                            leftEdge,
  247.         short                            topEdge
  248.     )
  249. {
  250.         Rect                            viewRect;
  251.         
  252.         if (LIST.rView.left != leftEdge || LIST.rView.top != topEdge) {
  253.             viewRect = LIST.rView;
  254.             InsetRect(&viewRect, -1, -1);
  255.             InvalRect(&viewRect);
  256.             OffsetRect(
  257.                 &LIST.rView,
  258.                 leftEdge - LIST.rView.left,
  259.                 topEdge -LIST.rView.top
  260.             );
  261.             viewRect = LIST.rView;
  262.             InsetRect(&viewRect, -1, -1);
  263.             InvalRect(&viewRect);
  264.             MoveControl(
  265.                 LIST.vScroll,
  266.                 LIST.rView.right - (kScrollBarWidth - 1),
  267.                 LIST.rView.top - 1
  268.             );
  269.         }
  270. }
  271.  
  272. /*
  273.  * SizeLog: this is the true size (we understand scroll bars)
  274.  */
  275. void
  276. SizeLog(
  277.         ListHandle                        logListHandle,
  278.         short                            newWidth,
  279.         short                            newHeight
  280.     )
  281. {
  282.         Rect                            viewRect;
  283.         
  284.         LSize(newWidth - (kScrollBarWidth - 1), newHeight, logListHandle);
  285.         viewRect = LIST.rView;
  286.         InsetRect(&viewRect, -1, -1);
  287.         InvalRect(&viewRect);
  288. }
  289.         
  290. Boolean
  291. DoClickInLog(
  292.         ListHandle                        logListHandle,
  293.         const EventRecord                *eventRecord
  294.     )
  295. {
  296. #define EVENT    (*eventRecord)
  297.  
  298.         Point                            mousePt;
  299.         Boolean                            result;
  300.         Rect                            viewRect;
  301.         
  302.         mousePt = EVENT.where;
  303.         GlobalToLocal(&mousePt);
  304.         viewRect = LIST.rView;
  305.         viewRect.right += (kScrollBarWidth - 1);
  306.         if ((result = PtInRect(mousePt, &viewRect)))
  307.             (void) LClick(mousePt, EVENT.modifiers, logListHandle);
  308.         return (result);
  309. #undef EVENT
  310. }
  311.  
  312. /*
  313.  * Log errors.
  314.  */
  315. void
  316. LogStatus(
  317.         ListHandle                        logListHandle,
  318.         OSErr                            theError,
  319.         const StringPtr                    infoText
  320.     )
  321. {
  322.         Str255                            msg;
  323.         Str15                            errorValue;
  324.         
  325.         if (theError != noErr) {
  326.             pstrcpy(msg, infoText);
  327.             pstrcat(msg, "\p: ");
  328.             NumToString(theError, errorValue);
  329.             pstrcat(msg, errorValue);
  330.             DisplayLogString(logListHandle, msg);
  331.         }
  332. }
  333.  
  334. /*
  335.  * DisplayLogString
  336.  * Call this function to store a string in the list.
  337.  */
  338. void
  339. DisplayLogString(
  340.         ListHandle                        logListHandle,
  341.         const StringPtr                    theString
  342.     )
  343. {
  344.  
  345.         Cell                        theCell;
  346.         short                        theRow;
  347.         Boolean                        scrollAtBottom;
  348.         
  349.         /*
  350.          * If there are already logLines in the
  351.          * list, delete the first row of the list.
  352.          * Then, in any case, append this datum at the
  353.          * bottom.
  354.          *
  355.          * The scroll bars are managed as follows:
  356.          * scroll bar is at the bottom, the new datum
  357.          * is selected and autoscrolled into view.
  358.          * Otherwise, the current cell is unchanged.
  359.          */
  360.         theRow = LIST.dataBounds.bottom;
  361.         scrollAtBottom =
  362.             (GetCtlValue(LIST.vScroll) == GetCtlMax(LIST.vScroll));
  363.         if (theRow >= LOGINFO.logLines)
  364.             LDelRow(1, 0, logListHandle);
  365.         theRow = LAddRow(1, LIST.dataBounds.bottom, logListHandle);
  366.         if (MemError() != noErr)
  367.             goto failure;
  368.         theCell.h = 0;
  369.         theCell.v = theRow;
  370.         LSetCell((Ptr) &theString[1], theString[0], theCell, logListHandle);
  371.         if (MemError() != noErr)
  372.             goto failure;
  373.         if (scrollAtBottom) {
  374.             theCell.v = 0;
  375.             if (LGetSelect(TRUE, &theCell, logListHandle))
  376.                 LSetSelect(FALSE, theCell, logListHandle);
  377.             theCell.v = theRow;
  378.             LSetSelect(TRUE, theCell, logListHandle);
  379.             LDoDraw(TRUE, logListHandle);
  380.             LAutoScroll(logListHandle);
  381.         }
  382.         LDraw(theCell, logListHandle);
  383. failure:
  384.         return;
  385. }
  386.  
  387. /*
  388.  * Draw the string stored in the list. The only difference between this function
  389.  * and a "normal" LDEF is that we don't visually indicate selection. Also, we use
  390.  * the "wide string" scrunchable string drawing procedure.
  391.  */
  392. static pascal void
  393. LogListDefProc(
  394.         short                            listMessage,
  395.         Boolean                            listSelect,
  396.         Rect                            *listRect,
  397.         Cell                            listCell,
  398.         short                            listDataOffset,
  399.         short                            listDataLen,
  400.         ListHandle                        logListHandle
  401.     )
  402. {
  403. #pragma unused (listCell)
  404.  
  405.         Boolean                            cellLockState;
  406.         Rect                            viewRect;
  407.         RGBColor                        saveForeColor;
  408.         RGBColor                        saveBackColor;
  409.         
  410.         /*
  411.          * If the userHandle isn't setup, do nothing: this is an initialization
  412.          * or a spurious command while we're disposing of the list.
  413.          */
  414.         if (LIST.userHandle != NULL) {
  415.             TextFont(LOGINFO.fontNumber);
  416.             TextSize(LOGINFO.fontSize);
  417.             if (COLOR_LIST) {
  418.                 GetForeColor(&saveForeColor);
  419.                 GetBackColor(&saveBackColor);
  420.                 RGBForeColor(&LOGINFO.foreColor);
  421.                 RGBBackColor(&LOGINFO.backColor);
  422.             }
  423.             switch (listMessage) {
  424.             case lInitMsg:
  425.                 break;
  426.             case lDrawMsg:
  427.                 EraseRect(listRect);
  428.                 if (listDataLen > 0) {
  429.                     viewRect = *listRect;
  430.                     viewRect.left += LIST.indent.h;
  431.                     /*
  432.                      * We don't indent in the vertical direction: by default,
  433.                      * it contains the font ascent which is only useful
  434.                      * for MoveTo... DrawString drawing.
  435.                      */
  436.                     cellLockState = HGetState(LIST.cells);
  437.                     HLock(LIST.cells);
  438.                     DrawWideText(
  439.                         (Ptr) (*LIST.cells),
  440.                         listDataOffset,
  441.                         listDataLen,
  442.                         &viewRect,
  443.                         normal
  444.                     );
  445.                     HSetState(LIST.cells, cellLockState);
  446.                 }
  447.                 if (listSelect == FALSE)
  448.                     break;
  449.                 /* Continue to do hilite */
  450.             case lHiliteMsg:
  451. #if 0        /* Hiliting is disabled */
  452. #ifdef THINK_C
  453.                 HiliteMode &= ~(1 << hiliteBit);
  454. #else /* MPW */
  455.                 *((char *) HiliteMode) &= ~(1 << hiliteBit); /* Inside Mac V-61    */
  456. #endif
  457.                 InvertRect(listRect);
  458. #endif
  459.                 break;
  460.             }
  461.             if (COLOR_LIST) {
  462.                 RGBForeColor(&saveForeColor);
  463.                 RGBBackColor(&saveBackColor);
  464.             }
  465.         }
  466. }
  467.  
  468. /*
  469.  * DrawWideText
  470.  * Draw the text within the alloted space. First try "full
  471.  * width", then "condensed", then shrink the and append '...'
  472.  */
  473. static void
  474. DrawWideText(
  475.         Ptr                                textPtr,
  476.         unsigned short                    offset,
  477.         unsigned short                    textLength,
  478.         const Rect                        *boundsRect,
  479.         short                            textFace
  480.     )
  481. {
  482.         short                oldFace;
  483.         Boolean                needEllipsis;
  484.         Ptr                    theTextPtr;
  485.         short                fieldWidth;
  486.         FontInfo            fontInfo;
  487.  
  488.         if (textPtr == NULL) {
  489.             textPtr = (Ptr) "<null>";
  490.             offset = 0;
  491.             textLength = 6;
  492.         }
  493.         if (textLength < 0 || textLength > 256) {
  494.             /*
  495.              * This is probably a bug.
  496.              */
  497.             textLength = 256;
  498.         }
  499.         /*
  500.          * It would be more elegant to erase only the area to the right of the
  501.          * text, but that * gets rather messy if we have to deal with ellipses.
  502.          */
  503.         EraseRect(boundsRect);
  504.         fieldWidth = width(*boundsRect);
  505.         theTextPtr = &textPtr[offset];
  506.         oldFace = (*qd.thePort).txFace;
  507.         TextFace(textFace);
  508.         needEllipsis = FALSE;
  509.         if (TextWidth(theTextPtr, 0, textLength) > fieldWidth) {
  510.             TextFace(textFace | condense);
  511.             if (TextWidth(theTextPtr, 0, textLength) > fieldWidth) {
  512.                 fieldWidth -= CharWidth(kCharEllipsis);
  513.                 needEllipsis = TRUE;
  514.                 while (textLength > 1
  515.                  && TextWidth(theTextPtr, 0, textLength) > fieldWidth)
  516.                     --textLength;
  517.             }
  518.         }
  519.         GetFontInfo(&fontInfo);
  520.         EraseRect(boundsRect);
  521.         MoveTo(boundsRect->left, boundsRect->top + fontInfo.ascent);
  522.         DrawText(theTextPtr, 0, textLength);
  523.         if (needEllipsis)
  524.             DrawChar(kCharEllipsis);
  525.         TextFace(oldFace);
  526. }
  527.  
  528.